﻿using System;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using UtilZ.Dotnet.AudioPlayer.Core;
using UtilZ.Dotnet.AudioPlayer.Native;
using UtilZ.Dotnet.AudioPlayer.Player;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.Log;

namespace ConAppCore.Test
{
    internal class TestSignalHelper
    {
        internal static void Test()
        {
            try
            {
                //TestResample();
                //TestAudioDataResamplePlay();
                //TestRS();
                //TestCaculatePowerComplex();
                //TestCaculatePowerReal();
                //TestFFTShiftReal();
                //TestFFTShiftComplex();

                TestStreamPlayer();
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }



        private static void TestStreamPlayer()
        {
            string filePath = @"D:\Temp\20240626142009_HY_02BJWD50371151_F_0095500000_B_0000200000_S_0000032000.wav";

            //BASSHelper.LoadPlugins();
            //BASSHelper.Init();
            SoundPlayerAbs.InitDevice(-1, 48000, BASSInit.BASS_DEVICE_DEFAULT);

            //var data = File.ReadAllBytes(filePath);
            //var player = new StreamSoundPlayer(1, new WaveInfo(filePath, 32000, 1, SampleBits.Sample16Bit), data.Length);
            //player.AppendData(data, 44, data.Length - 44);

            var player = new FileSoundPlayer(1);
            player.LoadFile(filePath);

            //player.Speed = 1.0f;
            player.Play();
            Console.ReadKey();

            SoundPlayerAbs.Free();
        }


        /// <summary>
        /// 流式播放回调
        /// </summary>
        private static STREAMPROC _streamProc;
        private static byte[] _data;
        private static int _dataOffset = 0;
        private static int _dataLength;
        private static int StreamProcCallback(int handle, IntPtr bufferPtr, int length, IntPtr user)
        {
            //StreamSoundPlayer soundPlayer;
            //if (_streamSoundPlayerDic.TryGetValue(handle, out soundPlayer))
            //{
            //    return soundPlayer.GetStreamProcCallbackData(bufferPtr, length, user);
            //}
            //else
            //{
            //    return 0;
            //}

            if (length > _dataLength)
            {
                length = _dataLength;
            }

            Marshal.Copy(_data, _dataOffset, bufferPtr, length);
            _dataLength -= length;
            _dataOffset += length;
            return length;
        }
       

        /*
        private static void TestAudioDataResamplePlay()
        {
            try
            {
                int dstSampleRate = 48000;
                //dstSampleRate = 8000;
                //dstSampleRate = 25000;
                //dstSampleRate = 10000;

                const int WAVE_HEAD_SIZE = 44;
                string filePath = @"D:\datas\16k_1chs_16bit.wav";
                filePath = @"D:\datas\16k_1chs_16bit.dat";
                filePath = @"D:\StarSky.pcm";
                byte[] buffer = File.ReadAllBytes(filePath);

                //using var fs = File.OpenWrite(@"D:\datas\16k_1chs_16bit.dat");
                //fs.Write(buffer, WAVE_HEAD_SIZE, buffer.Length - WAVE_HEAD_SIZE);
                //fs.Close();

                //var player = new StreamSoundPlayer(1, new WaveInfo(16000, 1, SampleBits.Sample16Bit), buffer.Length);
                ////player.AppendData(buffer, WAVE_HEAD_SIZE, buffer.Length - WAVE_HEAD_SIZE);
                //player.AppendData(buffer);
                //player.Play();

                short[] datas = new short[(buffer.Length - WAVE_HEAD_SIZE) / 2];
                using var ms = new MemoryStream(buffer);
                //ms.Position = WAVE_HEAD_SIZE;
                var reader = new BinaryReader(ms);
                for (int i = 0; i < datas.Length; i++)
                {
                    datas[i] = reader.ReadInt16();
                }

                short[] ret = SignalHelper.Resample<short>(datas, 44100, dstSampleRate, new TestResampleFilter(dstSampleRate, 4000));
                byte[] buffer2 = new byte[ret.Length * 2];
                using var ms2 = new MemoryStream(buffer2);
                var writer = new BinaryWriter(ms2);
                for (int i = 0; i < ret.Length; i++)
                {
                    writer.Write(ret[i]);
                }
                writer.Flush();

                var player = new StreamSoundPlayer(1, new WaveInfo(filePath, dstSampleRate, 1, SampleBits.Sample16Bit), buffer2.Length);
                player.AppendData(buffer2);
                player.Play();

                var xx = Console.ReadKey();
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }





        private static void TestResample()
        {
            IResampleFilter<short> filter = new TestResampleFilter(100, 100);
            short[] datas = new short[] { 1, 2, 3, 4, 5, 6, 7, 8 };
            short[] ret1 = SignalHelper.Resample<short>(datas, 8000, 16000, filter);
            short[] ret2 = SignalHelper.Resample<short>(datas, 16000, 8000, filter);
            short[] ret3 = SignalHelper.Resample<short>(datas, 8000, 25000, filter);
            short[] ret4 = SignalHelper.Resample<short>(datas, 25000, 8000, filter);
        }

        */

        private static void TestFFTShiftComplex()
        {
            var ret1 = SignalHelper.FFTShift(new Complex[] { 1, 2, 3, 4 });
            var ret2 = SignalHelper.FFTShift(new Complex[] { 1, 2, 3, 4, 5 });

            var ret3 = SignalHelper.FFTShift(new Complex[] { 1, 2, 3, 4, 5, 6 }, 1, 4);
            var ret4 = SignalHelper.FFTShift(new Complex[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 5);
        }

        private static void TestFFTShiftReal()
        {
            double[] ret1 = SignalHelper.FFTShift(new double[] { 1, 2, 3, 4 });
            double[] ret2 = SignalHelper.FFTShift(new double[] { 1, 2, 3, 4, 5 });

            double[] ret3 = SignalHelper.FFTShift(new double[] { 1, 2, 3, 4, 5, 6 }, 1, 4);
            double[] ret4 = SignalHelper.FFTShift(new double[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 5);
        }

        private static void TestCaculatePowerReal()
        {
            //var reals = new double[6];
            //for (int i = 0; i < reals.Length; i++)
            //{
            //    reals[i] = i;
            //}

            //double[] rets = MathEx.CaculatePower(reals, 0, 8000, 10);

            double[] ret1 = SignalHelper.CaculatePower(new double[] { 1, 2, 3, 4 }, 0, 4, 0, 8000, 10);
            double[] ret2 = SignalHelper.CaculatePower(new double[] { 1, 2, 3, 4, 5 }, 0, 5, 0, 8000, 10);
            double[] ret3 = SignalHelper.CaculatePower(new double[] { 1, 2, 3, 4, 5, 6 }, 1, 4, 0, 8000, 10);
            double[] ret4 = SignalHelper.CaculatePower(new double[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 5, 0, 8000, 10);
        }

        private static void TestCaculatePowerComplex()
        {
            //var complexs = new Complex[6];
            //for (int i = 0; i < complexs.Length; i++)
            //{
            //    complexs[i] = new Complex(i, i);
            //}

            //double[] rets = MathEx.CaculatePower(complexs, 0, 8000, 10);

            double[] ret1 = SignalHelper.CaculatePower(new Complex[] { 1, 2, 3, 4 }, 0, 4, 0, 8000, 10);
            double[] ret2 = SignalHelper.CaculatePower(new Complex[] { 1, 2, 3, 4, 5 }, 0, 5, 0, 8000, 10);
            double[] ret3 = SignalHelper.CaculatePower(new Complex[] { 1, 2, 3, 4, 5, 6 }, 1, 4, 0, 8000, 10);
            double[] ret4 = SignalHelper.CaculatePower(new Complex[] { 1, 2, 3, 4, 5, 6, 7 }, 1, 5, 0, 8000, 10);
        }
    }

    public class TestResampleFilter : IResampleFilter<short>
    {
        private double _sampleRate;
        private double _cutoffRate;

        public TestResampleFilter(double sampleRate, double cutoffRate)
        {
            this._sampleRate = sampleRate;
            this._cutoffRate = cutoffRate;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="values"></param>
        public void Filter(short[] values)
        {
            //var filter = MathNet.Filtering.IIR.OnlineIirFilter.CreateBandstop(MathNet.Filtering.ImpulseResponse.Finite, this._sampleRate, this._cutoffRate, 4000);
            //var filter = MathNet.Filtering.FIR.OnlineFirFilter.CreateBandstop(MathNet.Filtering.ImpulseResponse.Finite, this._sampleRate, this._cutoffRate, 8000);
            //var filter = MathNet.Filtering.FIR.OnlineFirFilter.CreateLowpass(MathNet.Filtering.ImpulseResponse.Finite, this._sampleRate, this._cutoffRate);

            //double[] vv = values.Select(t => { return (double)t; }).ToArray();
            //double[] ret = filter.ProcessSamples(vv);
            //for (int i = 0; i < values.Length; i++)
            //{
            //    values[i] = (short)ret[i];
            //}

            //Parallel.For(0, values.Length, (i) =>
            //{
            //    values[i] = (short)ret[i];
            //});



            //double[] vv = values.Select(t => { return (double)t; }).ToArray();
            //double[] ret = filter.ProcessSamples(vv);
            //for (int i = 0; i < values.Length; i++)
            //{
            //    values[i] = (short)ret[i];
            //}
        }
    }


}
